package com.example.springboot.config.aop;

import com.example.springboot.config.anotation.encrypt.EncryptField;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

import static com.example.springboot.pojo.EncryptConstant.DECRYPT;
import static com.example.springboot.pojo.EncryptConstant.ENCRYPT;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/8/4 14:13
 */
@Component
@Aspect
@Slf4j
public class EncryptAop {
    @Autowired
    private StringEncryptor stringEncryptor;

    @Pointcut("@annotation(com.example.springboot.config.anotation.encrypt.EncryptMethod)")
    public void pointcut() {

    }

    /**
     * 切面
     *
     * @param joinPoint
     * @return
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        /**
         * 加密
         */
        encrypt(joinPoint);
        Object proceed = joinPoint.proceed();
        /**
         * 解密
         */
        Object decrypt = decrypt(joinPoint);
        return proceed;
    }

    private Object decrypt(ProceedingJoinPoint joinPoint) {
        Object result = null;
        // 拿到参数
        Object[] args = joinPoint.getArgs();
        // 遍历
        if (args.length != 0) {
            for (Object arg : args) {
                // 是否是字符
                if (arg instanceof String) {
                    decryptValue(arg);
                } else {
                    result = handler(arg, DECRYPT);
                }
            }
        }
        return result;
    }

    private String decryptValue(Object arg) {
        String value = null;
        try {
            value = stringEncryptor.decrypt(String.valueOf(arg));
        } catch (Exception e) {
            log.error("【加密出错{}】", arg);
        }
        return value;
    }

    private Object handler(Object arg, String type) {
        if (Objects.isNull(arg)) {
            return null;
        }
        // 拿到字段
        Field[] declaredFields = arg.getClass().getDeclaredFields();
        // 遍历
        for (Field field : declaredFields) {
            // 是否被加密主机
            if (field.isAnnotationPresent(EncryptField.class)) {
                field.setAccessible(true);
                // 拿到值
                try {
                    String o = (String) field.get(arg);
                    String value = null;
                    // 是否是解密
                    if (Objects.equals(DECRYPT, type)) {
                        value = stringEncryptor.decrypt(o);
                    } else {
                        value = stringEncryptor.encrypt(o);
                    }
                    field.set(arg, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
        return arg;
    }

    private String encryptValue(Object arg) {
        String value = null;
        try {
            value = stringEncryptor.encrypt(String.valueOf(arg));
        } catch (Exception e) {
            log.error("【加密出错{}】", arg);
        }
        return value;
    }

    private void encrypt(ProceedingJoinPoint joinPoint) {
        // 拿到参数
        Object[] args = joinPoint.getArgs();
        // 遍历
        if (args.length != 0) {
            for (Object arg : args) {
                // 是否是字符
                if (arg instanceof String) {
                    encryptValue(arg);
                } else {
                    handler(arg, ENCRYPT);
                }
            }
        }
    }
}
